package server;

// This file contains material supporting section 10.9 of the textbook:
// "Object Oriented Software Engineering" and is issued under the open-source
// license found at www.lloseng.com

/*
 * SimpleServer.java   2001-02-08
 *
 * Copyright (c) 2000 Robert Laganiere and Timothy C. Lethbridge.
 * All Rights Reserved.
 *
 */
import db.parking.beans.Complaints;
import db.parking.beans.Customer;
import db.parking.beans.Employee;
import db.parking.beans.Orders;
import db.parking.beans.Parking;
import db.parking.beans.ParkingLot;
import db.parking.beans.QuarterReports;
import db.parking.beans.SaveDisableParking;
import db.parking.beans.StatsticPerDay;
import db.parking.beans.Subscriber;
import db.parking.beans.SystemDetails;
import db.parking.beans.WeeklyStatistics;
import db.parking.beans.rates;
import db.tables.AdminCanceledOrders;
import db.tables.AdminCheckInOut;
import db.tables.AdminComplaints;
import db.tables.AdminCustomer;
import db.tables.AdminEmployee;
import db.tables.AdminOrders;
import db.tables.AdminParking;
import db.tables.AdminRates;
import db.tables.AdminReports;
import db.tables.AdminSMS;
import db.tables.AdminSaveDisableParking;
import db.tables.AdminStatistics;
import db.tables.AdminSubscriber;
import db.tables.AdminSystemDetails;
import db.tables.AdminWeeklyStatistics;
import db.tables.ParkingLotAdmin;

import java.lang.Thread;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Random;
import java.util.Timer;
import java.util.concurrent.TimeUnit;
import java.awt.List;
import java.awt.Color;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Timestamp;

import vcp.scheduledtasks.DailyTimer;
import vcp.scheduledtasks.ReportGenerator;
import vcp.scheduledtasks.smsThread;


import control.ConnectionManage;
import control.DBType;
import control.customTimestamp;
import client.Message;

/**
 * The <code> SimpleServer </code> class is a simple subclass of the
 * <code> ocsf.server.AbstractServer </code> class. It allows testing of the
 * functionalities offered by the OCSF framework. The
 * <code> java.awt.List </code> instance is used to display informative
 * messages. This list is red when the server is closed, yellow when the server
 * is stopped and green when open.
 * 
 * @author Dr. Robert Lagani&egrave;re
 * @version February 2001
 * @see ocsf.server.AbstractServer
 */

public class SimpleServer extends AbstractServer {
	private Message msg;
	private List liste;
	Timer timer, timer2;
	private final int ParkingLotNum = 6;
	private ParkingLot[] lotArray;

	// for time stamp= server current time
	long time;// = System.currentTimeMillis();

	// Timestamp currTimestamp;// = new Timestamp(time);

	/**
	 * Creates a simple server. The default port is 12345.
	 * 
	 * @param liste
	 *            the liste on which information will be displayed.
	 */
	public SimpleServer(List liste) {
		super(12345);
		this.liste = liste;

	}

	/**
	 * Creates a simple server. 
	 * @param port
	 *            the port on which the server will listen.
	 * @param liste
	 *            the liste on which information will be displayed.
	 */
	public SimpleServer(int port, List liste) {
		super(port);
		this.liste = liste;
		
	}

	/**
	 * Hook method called each time a new client connection is accepted.
	 * 
	 * @param client
	 *            the connection connected to the client.
	 */
	synchronized protected void clientConnected(ConnectionToClient client) {
		liste.add("Client connected: " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called each time a client disconnects.
	 * 
	 * @param client
	 *            the connection with the client.
	 */
	synchronized protected void clientDisconnected(ConnectionToClient client) {
		liste.add("Client disconnected: " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called each time an exception is thrown in a
	 * ConnectionToClient thread.
	 * 
	 * @param client
	 *            the client that raised the exception.
	 * @param Throwable
	 *            the exception thrown.
	 */
	synchronized protected void clientException(ConnectionToClient client,
			Throwable exception) {
		liste.add("Client exception: " + exception + " with " + client);
		liste.makeVisible(liste.getItemCount() - 1);
	}

	/**
	 * Hook method called when the server stops accepting connections because an
	 * exception has been raised.
	 * 
	 * @param exception
	 *            the exception raised.
	 */
	protected void listeningException(Throwable exception) {
		liste.add("Listening exception: " + exception);
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.red);
	}

	/**
	 * Hook method called when the server stops accepting connections.
	 */
	protected void serverStopped() {
		liste.add("Server stopped");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.yellow);
	}

	/**
	 * Hook method called when the server is clased.
	 */
	protected void serverClosed() {
		liste.add("Server closed");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.red);
	}

	/**
	 * Hook method called when the server starts listening for connections.
	 */
	protected void serverStarted() {
		liste.add("Server started on port : " + this.getPort());
		liste.add("Waiting for users to connect...");
		liste.makeVisible(liste.getItemCount() - 1);
		liste.setBackground(Color.green);
		try {
			// Initialize the parking lot object
			InitParkingLot();
			// Initialize SMS thread
			Thread sendSMS = new Thread(new smsThread());
			sendSMS.start();
			// Intialize weekly timer
			timer = new Timer();
			Calendar date = Calendar.getInstance();
			date.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
			date.set(Calendar.HOUR_OF_DAY, 0);
			date.set(Calendar.MINUTE, 0);
			date.set(Calendar.SECOND, 0);
			date.set(Calendar.MILLISECOND, 0);
			// Schedule to run every Sunday in midnight
			timer.schedule(new ReportGenerator(), date.getTime(), 1000 * 60
					* 60 * 24 * 7);

			// Initialize daily timer
			timer2 = new Timer();
			Calendar date2 = Calendar.getInstance();
			date2.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
			date2.set(Calendar.HOUR_OF_DAY, 12);
			date2.set(Calendar.MINUTE, 23);
			date2.set(Calendar.SECOND, 0);
			date2.set(Calendar.MILLISECOND, 0);
			// Schedule to run every Sunday in midnight
			timer.schedule(new DailyTimer(lotArray), date.getTime(),
					1000 * 60 * 60 * 24);

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Handles a command sent from one client to the server.
	 * 
	 * @param msg
	 *            the message sent.
	 * @param client
	 *            the connection connected to the client that sent the message.
	 */
	protected void handleMessageFromClient(Object msg, ConnectionToClient client) {
		
		this.msg = (Message) msg;

		switch (this.msg.getMsg()) {

		case "GetParkingObject":
			GetLotsObject(this.msg);
			break;
		
			
		case "GetLotByLotNum":
			GetLotByLotNum(this.msg);
			break;

		// orders handle
		case "AddOccasionalOrder":
			AddOccasionalOrder(this.msg);
			break;

		case "AddTemporaryOrder":
			AddTemporaryOrder(this.msg);
			break;

		case "CancelOrder": {
			CancelOrder(this.msg);
			break;
		}

		case "SubmitComplaint": {
			SubmitComplaint(this.msg);
			break;
		}

		case "AddFullSubscriber": {
			AddFullSubscriber(this.msg);
			break;
		}

		case "AddRegularSubscriber": {
			AddRegularSubscriber(this.msg);
			break;
		}
		case "TrackOrder": {
			TrackOrder(this.msg);
			break;
		}
		case "Login": {
			Login(this.msg);
			break;
		}
		case "CheckInRegular": {
			CheckInRegular(this.msg);
			break;
		}
		case "CheckInSubscriber": {
			CheckInSubscriber(this.msg);
			break;
		}
		case "CheckOut": {
			CheckOut(this.msg);
			break;
		}

		case "GetComplaints": {
			GetComplaints(this.msg);
			break;
		}
		case "UpdateResolvedStatus": {
			UpdateResolvedStatus(this.msg);
			break;
		}
		case "UpdateResolveAmount": {
			UpdateResolveAmount(this.msg);
			break;
		}

		case "GetRatesByLotNum": {
			GetRatesByLotNum(this.msg);
			break;
		}

		case "GetRates": {
			GetRates(this.msg);
			break;
		}
		case "SaveRate": {
			SaveRate(this.msg);
			break;
		}

		case "GetModifiedRates": {
			GetModifiedRates(this.msg);
			break;
		}
		case "ApproveRate": {
			ApproveRate(this.msg);
			break;
		}

		case "ModifyTempRateCell": {
			ModifyTempRateCell(this.msg);
			break;
		}

		case "GetSystemDetails": {
			GetSystemDetails(this.msg);
			break;
		}

		case "CreateQuarterReport": {
			CreateQuarterReport(this.msg);
			break;
		}
		
		case "GetQuarterReport": {
			GetQuarterReport(this.msg);
			break;
		}
		
		case "GetMonthlyReport":{
			GetMonthlyReport(this.msg);
			break;
		}
		
		case "GetAllTabels":{
			GetAllTabels(this.msg);
			break;
		}

		case "SavePlState": {
			SavePlState(this.msg);
			break;
		}
		
		case "ResetX":
			ResetX(this.msg);
			break;
		

		default:
			this.msg.setStatus(false);
		}

		sendToAllClients(this.msg);
	}

	/**
	 * Employee can adjust the "width" of the lot he is part of by "resetting X"
	 * @param msg
	 */
	@SuppressWarnings("unchecked")
	
	private void ResetX(Message msg) {
		Message tempMsg = (Message) msg;
		ArrayList<Object> arr = null;
		if(!tempMsg.getObj().equals(null)){
		   arr = (ArrayList<Object>)tempMsg.getObj();	
		}
		try {
			if (!AdminParking.updateAlloc(arr)) {
				liste.add("ResetX::not modified");
				tempMsg.setStatusMsg("ResetX::not modified");
				tempMsg.setStatus(false);
			}else{
				liste.add("ResetX::OK");
				tempMsg.setMsg("ResetX");
				tempMsg.setStatus(true);
                lotArray = null;
				InitParkingLot();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	
	
	/**
	 * When Customer Issues resolve a complaint,through this function they refund the customer's money
	 * @param msg
	 * 
	 */
	private void UpdateResolveAmount(Message msg) {
		Message tempMsg = (Message) msg;
		float amountToUpdate;
		Complaints bean = new Complaints();
		Complaints comp = (Complaints) tempMsg.getObj();
		try {
			bean = AdminComplaints.getRow(comp.getComplaintID());
			if (bean == null) {
				liste.add("UpdateResolveAmount::not modified");
				tempMsg.setStatusMsg("UpdateResolveAmount::not modified");
				tempMsg.setStatus(false);
			}else{
				amountToUpdate = comp.getAmount();
				try {
					AdminCustomer.update(bean.getCustomerID(), AdminCustomer.getCustomerBalance(bean.getCustomerID()).getAmount() + amountToUpdate);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				liste.add("UpdateResolveAmount::OK");
				tempMsg.setMsg("UpdateResolveAmount");
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Update Complaint stats to resolved after resolution
	 * @param msg
	 */
	private void UpdateResolvedStatus(Message msg) {
		Message tempMsg = (Message) msg;
		Complaints comp = (Complaints) tempMsg.getObj();
		try {
			if (!AdminComplaints.update(comp)) {
				liste.add("UpdateResolvedStatus::not modified");
				tempMsg.setStatusMsg("UpdateResolvedStatus::not modified");
				tempMsg.setStatus(false);
			}else{
				liste.add("UpdateResolvedStatus::OK");
				tempMsg.setMsg("UpdateResolvedStatus");
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	
	/**
	 * Prints all tables for statistics
	 * @param msg
	 */
	private void GetAllTabels(Message msg){
		Message tempMsg = (Message) msg;
		
		try {
			switch (tempMsg.getMsg()) {
			case "orders": // return all orders for read only
				Orders[] retOrders = AdminOrders.getAllOrders();
				if (retOrders != null) {
					liste.add("GetAllTabels->Orders::OK");
					tempMsg.setMsg("GetAllTabels->Orders");
					tempMsg.setObj(retOrders);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->Orders::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Orders::ERROR");
					tempMsg.setMsg("GetAllTabels->Orders");
					tempMsg.setStatus(false);
				}
				break;

			case "complaints": // return all complaints for read only
				Complaints[] retComplaints = AdminComplaints.getAllComplaints();
				if (retComplaints != null) {
					liste.add("GetAllTabels->Complaints::OK");
					tempMsg.setMsg("GetAllTabels->Complaints");
					tempMsg.setObj(retComplaints);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->Complaints::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Complaints::ERROR");
					tempMsg.setMsg("GetAllTabels->Complaints");
					tempMsg.setStatus(false);
				}
				break;

			case "customer": // return all customer for read only

				Customer[] retCustomers = AdminCustomer.getAllCustomers();
				if (retCustomers != null) {
					liste.add("GetAllTabels->Customer::OK");
					tempMsg.setMsg("GetAllTabels->Customer");
					tempMsg.setObj(retCustomers);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->Customer::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Customer::ERROR");
					tempMsg.setMsg("GetAllTabels->Customer");
					tempMsg.setStatus(false);
				}

				break;
			case "employee":
				// return all employee

				Employee[] retEmployee = AdminEmployee.getAllEmployees();
				if (retEmployee != null) {
					liste.add("GetAllTabels->Employee::OK");
					tempMsg.setMsg("GetAllTabels->Employee");
					tempMsg.setObj(retEmployee);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->Employee::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Employee::ERROR");
					tempMsg.setMsg("GetAllTabels->Employee");
					tempMsg.setStatus(false);
				}

				break;
			case "parkinglot":
				// return all parkinglot !!!like its in the db not in the
				// bean!!!
				ParkingLot[] retParkingLot = ParkingLotAdmin.getAllParkingLot();
				if (retParkingLot != null) {
					liste.add("GetAllTabels->Parkinglot::OK");
					tempMsg.setMsg("GetAllTabels->Parkinglot");
					tempMsg.setObj(retParkingLot);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->Parkinglot::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Parkinglot::ERROR");
					tempMsg.setMsg("GetAllTabels->Parkinglot");
					tempMsg.setStatus(false);
				}
				break;

			case "rates":
				// return all complaints
				rates[] retRates = AdminRates.getRows();
				if (retRates != null) {
					liste.add("GetAllTabels->rates::OK");
					tempMsg.setMsg("GetAllTabels->rates");
					tempMsg.setObj(retRates);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->rates::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->rates::ERROR");
					tempMsg.setMsg("GetAllTabels->rates");
					tempMsg.setStatus(false);
				}
				break;

			case "statsticsperday":
				// return all statsticsperday
				StatsticPerDay[] statsticPerDay = AdminStatistics
						.getAllStatsticPerDay();
				if (statsticPerDay != null) {
					liste.add("GetAllTabels->StatsticPerDay::OK");
					tempMsg.setMsg("GetAllTabels->StatsticPerDay");
					tempMsg.setObj(statsticPerDay);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->StatsticPerDay::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->StatsticPerDay::ERROR");
					tempMsg.setMsg("GetAllTabels->StatsticPerDay");
					tempMsg.setStatus(false);
				}
				break;

			case "statsticsperweek":
				// return all statsticsperweek
				WeeklyStatistics[] weeklyStatistics = AdminWeeklyStatistics
						.getAllWeeklyStatistics();
				if (weeklyStatistics != null) {
					liste.add("GetAllTabels->Statsticsperweek::OK");
					tempMsg.setMsg("GetAllTabels->Statsticsperweek");
					tempMsg.setObj(weeklyStatistics);
					tempMsg.setStatus(true);
				} else {
					liste.add("GetAllTabels->StatsticPerDay::ERROR");
					tempMsg.setStatusMsg("GetAllTabels->Statsticsperweek::ERROR");
					tempMsg.setMsg("GetAllTabels->Statsticsperweek");
					tempMsg.setStatus(false);
				}
				break;

			default:
				break;
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("SimpleServer->GetAllTabels");
		}
	}

	

	/**
	 * Get and fill in the monthly statistics tables
	 * @param msg
	 */
	private void GetMonthlyReport(Message msg){
		Message tempMsg = (Message) msg;

		@SuppressWarnings("unchecked")
		ArrayList<Object> arr=(ArrayList<Object>)tempMsg.getObj();
		
		int year =(int)arr.get(0);
		int month =(int)arr.get(1);
		int lotNo=(int) arr.get(2);
		
		
		Timestamp startTime;
		Timestamp endTime;

		
		startTime=Timestamp.valueOf(year+"-"+month+"-01 00:00:00.0");
		
		if(month!=12){
			int nextMonth= month+1;
			endTime=Timestamp.valueOf(year+"-"+nextMonth+"-01 00:00:00.0");
		}
		else
		{
			int nextYear= year+1;
			endTime=Timestamp.valueOf(nextYear+"-01-01 00:00:00.0");
		}


		try {
			WeeklyStatistics[] weeklyStatisticsPerMonth= AdminWeeklyStatistics.getWeeklyStatistics(startTime,endTime,lotNo);
			if(weeklyStatisticsPerMonth!=null){
				liste.add("GetMonthlyReport::OK");
				tempMsg.setMsg("GetMonthlyReport");
				tempMsg.setObj(weeklyStatisticsPerMonth);
				tempMsg.setStatus(true);
			}else{
				liste.add("GetMonthlyReport::ERROR");
				tempMsg.setStatusMsg("GetMonthlyReport::ERROR");
				tempMsg.setMsg("GetMonthlyReport");
				tempMsg.setStatus(false);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("SimpleServer->GetMonthlyReport");
		}
				
	}
	
	/**
	 * Save parking state - Saved Or Under Maintenance
	 * @param msg
	 */
	private void SavePlState(Message msg) {
		long time =System.currentTimeMillis();
		Timestamp now=new Timestamp(time);
		
		Message tempMsg = (Message) msg;		
		@SuppressWarnings("unchecked")
		ArrayList<Object> arr = (ArrayList<Object>)tempMsg.getObj();
		
		
		Parking parking = (Parking) arr.get(0);
		int uid = (int)arr.get(1);
		
		lotArray[parking.getLotNo() - 1].setLocation(parking.getPositionX(),
				parking.getPositionY(), parking.getFloorNo(),
				parking.getStatus());// set staus of state
		lotArray[parking.getLotNo() - 1].setTotalCars(lotArray[parking
				.getLotNo() - 1].getTotalCars() + 1); // set total cars of
														// object
		SaveDisableParking st=new SaveDisableParking();
		st.setLotNo(parking.getLotNo());
		st.setLotNo(parking.getLotNo());
		st.setStatus(parking.getStatus());
		st.setX(parking.getPositionX());
		st.setY(parking.getPositionY());
		st.setZ(parking.getFloorNo());
		st.setEmployeeId(uid);  //get emploeye id from max
		
		if(st.getStatus()==2||st.getStatus()==3){
			st.setFrom(now);
		}
		else if(st.getStatus()==0){
			st.setTo(now);
		}
	
		
		try {			
			AdminParking.insert(parking);
			if(st.getStatus()==0)			
				AdminSaveDisableParking.update(st); //reset to the original state
			else									
				AdminSaveDisableParking.insert(st);	//update to new status
			tempMsg.setObj(null);
			tempMsg.setMsg("SavePlState");
			liste.add("Parking lot saved");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Helper function to get system details from currently running lot object
	 * @param msg
	 */
	private void GetSystemDetails(Message msg) {
		Message tempMsg = (Message) msg;

		long time2=System.currentTimeMillis();	//current time
		Timestamp now=new Timestamp(time2);
		
		Timestamp nowMinues28=new Timestamp(now.getTime());
		Calendar cal = Calendar.getInstance();
		cal.setTime(nowMinues28);
		cal.add(Calendar.DAY_OF_WEEK, -28); // now minus 28 dayes
		nowMinues28.setTime(cal.getTime().getTime());
		
		tempMsg.setObj(null);
		HashMap<String, Object> hm = new HashMap<String, Object>();
		SystemDetails sdetails = null;
		try {
			sdetails = AdminSystemDetails.getOveralSystemDetails();
			int subNum = AdminSubscriber.getSubscribersNumInAllLots(now, nowMinues28);
			int subNumMoreThanOnCar = AdminSubscriber.getSubscribersNumInAllLotsMoreThanOneCar(now, nowMinues28);
			if (sdetails == null) {
				liste.add("GetSystemState::no data");
				tempMsg.setStatusMsg("No System Data");
				tempMsg.setStatus(false);
			} else {
				liste.add("GetSystemState::OK");
				hm.put("Batch_details", sdetails);
				hm.put("subNum", subNum);
				hm.put("subNumMoreThanOnCar", subNumMoreThanOnCar);
				tempMsg.setStatusMsg("GetSystemState");
				tempMsg.setMsg("GetSystemState");
				tempMsg.setObj(hm);
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Function receives a lot and rerieves its number
	 * @param msg
	 */
	private void GetLotByLotNum(Message msg) {
		Message tempMsg = (Message) msg;
		int lotNum = (int) tempMsg.getObj();
		ParkingLot pl = lotArray[lotNum];
		if (pl != null) {
			liste.add("GetLotByLotNum::OK");
			tempMsg.setObj(pl);
			tempMsg.setStatusMsg("OK");
			tempMsg.setMsg("GetLotByLotNum");
			tempMsg.setStatus(true);
		} else {
			liste.add("GetLotByLotNum::ERROR retrieveing object");
			tempMsg.setObj(null);
			tempMsg.setStatusMsg("ERROR retrieveing object");
			tempMsg.setMsg("GetLotByLotNum");
			tempMsg.setStatus(false);
		}
	}

	/**
	 * Gui helper function to modify temporary rates set by parking manager
	 * @param msg
	 */
	private void ModifyTempRateCell(Message msg) {
		Message tempMsg = (Message) msg;
		rates bean = (rates) tempMsg.getObj();
		try {
			if (AdminRates.updateTempAmount(bean) == false) {
				liste.add("ModifyTempRateCell::no modification made");
				tempMsg.setStatusMsg("no modification made");
				tempMsg.setStatus(false);
				tempMsg.setObj(null);
			} else {
				liste.add("ModifyTempRateCell::OK");
				tempMsg.setStatusMsg("OK");
				tempMsg.setMsg("ModifyTempRateCell");
				tempMsg.setObj(null);
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Director approves the rates that were set by the parking manager of a specified lot
	 * @param msg
	 */
	private void ApproveRate(Message msg) {
		Message tempMsg = (Message) msg;
		rates bean = (rates) tempMsg.getObj();
		try {
			if (AdminRates.updateRateStatus(bean) == false) {
				liste.add("ApproveRate::no approval");
				tempMsg.setStatusMsg("No approval");
				tempMsg.setStatus(false);
				tempMsg.setObj(null);
			} else {
				liste.add("ApproveRate::OK");
				tempMsg.setStatusMsg("OK");
				tempMsg.setMsg("ApproveRate");
				tempMsg.setObj(null);
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * return the rates after change has been accepted by the director
	 * @param msg
	 */
	private void GetModifiedRates(Message msg) {
		Message tempMsg = (Message) msg;
		ArrayList<rates> results = null;
		try {
			results = AdminRates.getAllModified();
			if (results == null) {
				liste.add("GetModifiedRates::no rates modified yet");
				tempMsg.setStatusMsg("There is no rates yet..");
				tempMsg.setStatus(false);
			} else {
				liste.add("GetModifiedRates::OK");
				tempMsg.setStatusMsg("OK");
				tempMsg.setMsg("GetModifiedRates");
				tempMsg.setObj(results);
				tempMsg.setStatus(true);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Employee's can save the rates of their current lot
	 * @param msg
	 */
	private void SaveRate(Message msg) {
		Message tempMsg = (Message) msg;
		rates bean = (rates) tempMsg.getObj();
		rates result = null;
		try {
			result = AdminRates.getRow(bean.getLotNo(), bean.getRateType());
			if (result != null) {
				liste.add("SaveRate::already exists");
				tempMsg.setStatusMsg("rate already exists");
				tempMsg.setStatus(false);
				tempMsg.setObj(null);
			} else {
				AdminRates.insertRate(bean);
				liste.add("SaveRate::OK");
				tempMsg.setStatusMsg("Rate saved successfully");
				tempMsg.setStatus(true);
				tempMsg.setObj(null);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


	/**
	 * Employee can retrieve the rates of his current lot
	 * @param msg
	 */
	private void GetRates(Message msg) {
		Message tempMsg = (Message) msg;
		ArrayList<rates> results = null;
		try {
			try {
				results = AdminRates.getAll();
				if (results == null) {
					liste.add("GetRates::no rates");
					tempMsg.setStatusMsg("There is no rates yet..");
					System.out.println("No rates :: debug");
					tempMsg.setStatus(false);
				} else {
					liste.add("GetRates::OK");
					tempMsg.setStatusMsg("OK");
					tempMsg.setMsg("GetRates");
					tempMsg.setObj(results);
					tempMsg.setStatus(true);
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public int aa(int a,int b){
		int c = a+b;
		return c;
	}

	/**
	 * Get lot number and return it's rates (for employee use)
	 * @param msg
	 */
	private void GetRatesByLotNum(Message msg) {
		Message tempMsg = (Message) msg;
		int lotNum = (int) msg.getObj();
		ArrayList<rates> results = null;
		try {
			try {
				results = AdminRates.getByLotNum(lotNum);
				if (results == null) {
					liste.add("GetRatesByLotNum::no rates");
					tempMsg.setStatusMsg("There is no rates yet..");
					System.out.println("No rates :: debug");
					tempMsg.setStatus(false);
				} else {
					liste.add("GetRatesByLotNum::OK");
					tempMsg.setStatusMsg("OK");
					tempMsg.setMsg("GetRatesByLotNum");
					tempMsg.setObj(results);
					tempMsg.setStatus(true);
				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * GetParkingLevel**
	 * 
	 * return all parking spots and their status on a certain level inside a lot
	 * @param msg
	 * @return void get parking level
	 */
	private void GetLotsObject(Message msg) {
		Message tempMsg = (Message) msg;
		liste.add("GetParkingObject");
		if (lotArray != null) {
			tempMsg.setObj(lotArray);
			tempMsg.setMsg("GetParkingObject");
			tempMsg.setStatus(true);
		}

	}

	/**
	 * function receives a lot and a floor number and returns all parking spots and their status on specified floor
	 * 
	 * @param pl - parking lot object
	 * @param z - floor number
	 * @return
	 */
	public int[][] transpose3dTo2d(ParkingLot pl, int z) {
		int arr[][] = new int[pl.getX()][pl.getY()];
		for (int i = 0; i < pl.getY(); i++)
			for (int j = 0; j < pl.getX(); j++) {
				arr[j][i] = pl.getLocation(j, i, z);
				System.out.println(arr[j][i]);
			}
		return arr;
	}

	/****
	 * GetComplaints**
	 * 
	 * Helper function that gets all user complaints into a table
	 * 
	 * @param msg
	 * @return void get complaints
	 */

	private void GetComplaints(Object msg) {
		Message tempMsg = (Message) msg;
		ArrayList<Complaints> results = null;
		try {
			try {
				results = AdminComplaints.getAll(20, "DATE desc");
				if (results == null) {
					liste.add("GetComplaints::no complaints");
					tempMsg.setStatusMsg("There is no complaints yet..");
					System.out.println("No complaints :: debug");
					tempMsg.setStatus(false);
				} else {
					liste.add("GetComplaints::OK");
					tempMsg.setStatusMsg("OK");
					tempMsg.setMsg("GetComplaints");
					tempMsg.setObj(results);
					tempMsg.setStatus(true);

				}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/****
	 * AddOccasionalOrder**
	 * 
	 * Check user validity against DB and insert an occasional user
	 * @param msg
	 * @return void 
	 */
	public void AddOccasionalOrder(Object msg) {

		Message tempMsg = (Message) msg;
		try {
			Orders o = (Orders) tempMsg.getObj();

			// check if an Occasional customer with this ID exists
			Customer bean = AdminCustomer.getOccasionalRow(o.getUid());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such Customer Does Not Exist");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);

			o.setStartTime(currTimestamp);
			// check that entered leave time is not before the current time now
			if (currTimestamp.getTime() > o.getLeaveTime().getTime()) {
				liste.add("ERROR:Occaional User Has Entered Invalid Leave Time");
				tempMsg.setStatusMsg("Leave Time Must Be After Current Time");
				return;
			}
			if (AdminOrders.getLotStatus(o) == lotArray[o.getLotNo() - 1]
					.getCapacity()) {
				liste.add("ERROR:Occasional User Tried To Order While Lot Is Full");
				tempMsg.setStatusMsg("Sorry,But Lot Is Full At That Time");
				return;
			}
			// Check if lot if full
			if (lotArray[o.getLotNo() - 1].getTotalCars() == lotArray[o
					.getLotNo() - 1].getCapacity()) {
				// direct client to alternative lot
				int redirctionLot = 0;
				for (int i = 1; i <= ParkingLotNum; i++) {
					if (lotArray[i - 1].getTotalCars() < lotArray[i - 1]
							.getCapacity()) {
						redirctionLot = i;

					}

				}
				if (redirctionLot == 0)
					tempMsg.setStatusMsg("No Free Lots At The Moment");
				else {

					liste.add("ERROR:Parking Lot Is Full,Sending User To Lot No"
							+ redirctionLot);
					tempMsg.setStatusMsg("Sorry,But This Parking Lot Is Full,Please Go To Lot "
							+ redirctionLot);
				}
				return;
			} else {
				// add user to lot
				lotArray[o.getLotNo() - 1]
						.setTotalCars(lotArray[o.getLotNo() - 1].getTotalCars() + 1);
				ParkingLotAdmin.update(o.getLotNo(),
						lotArray[o.getLotNo() - 1].getTotalCars());

			}
			if (AdminOrders.insertOccasional(o)) {
				// Sort Orders that are > then CurrTime in Orders Array
				Orders[] NewestOrders = AdminOrders.getRow(currTimestamp,
						o.getLotNo());
				int orderIndex = 0;
				lotArray[o.getLotNo() - 1].printLocastions();
				locateParking(NewestOrders, orderIndex, o.getLotNo());
				lotArray[o.getLotNo() - 1].printLocastions();
				tempMsg.setStatus(true); // insert to DB was
				liste.add("Occasional Client Has Added Order No." + o.getOid());
				lotArray[o.getLotNo()].setTotalCars(lotArray[o.getLotNo()]
						.getTotalCars() + 1);
				AdminCheckInOut.insertCheckIn(o.getOid(), currTimestamp);// CheckIN

			} else {
				tempMsg.setStatus(false);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// allocate new parking spot
	/**
	 * Parking Algorithm
	 * 
	 * @param NewestOrders - array or orders that are sorted by leavetime which is greater then currtime.
	 * @param orderIndex - order iterator.
	 * @param lotId - number of lot.
	 * @throws Exception
	 */
	private void locateParking(Orders[] NewestOrders, int orderIndex, int lotId)
			throws Exception {
		// Reset Lot Before New Entrance
		Parking tmpParking = new Parking();
		int tmpIndex = orderIndex;

		if (NewestOrders.length == 0) { //
			AdminParking.deleteAllLocastions(lotId); //
			for (int z = 0; z < lotArray[lotId - 1].getZ(); z++)
				for (int y = 0; y < lotArray[lotId - 1].getY(); y++)
					for (int x = 0; x < lotArray[lotId - 1].getX(); x++)
						if (lotArray[lotId - 1].getLocation(x, y, z) == 1)
							lotArray[lotId - 1].setLocation(x, y, z, 0);
			return;
		}

		lotArray[NewestOrders[orderIndex].getLotNo() - 1].printLocastions();
		for (int y = 0; orderIndex < NewestOrders.length
				&& y < lotArray[NewestOrders[orderIndex].getLotNo() - 1].getY(); y++) {
			for (int z = 0; orderIndex < NewestOrders.length
					&& z < lotArray[NewestOrders[orderIndex].getLotNo() - 1]
							.getZ(); z++) {
				for (int x = 0; orderIndex < NewestOrders.length
						&& x < lotArray[NewestOrders[orderIndex].getLotNo() - 1]
								.getX(); x++) {
					if (lotArray[NewestOrders[orderIndex].getLotNo() - 1]
							.getLocation(x, y, z) == 1) {
						// Delete row from database so we cant insert a new
						// status
						AdminParking.delete(
								NewestOrders[orderIndex].getLotNo(), x, y, z);
						// replace updated values in our object
						lotArray[NewestOrders[orderIndex].getLotNo() - 1]
								.setLocation(x, y, z, 0);
						orderIndex++;
					}
				}
			}
		}

		// Allocate new parking spot
		for (int y = 0; tmpIndex < NewestOrders.length
				&& y < lotArray[NewestOrders[tmpIndex].getLotNo() - 1].getY(); y++) {
			for (int z = 0; tmpIndex < NewestOrders.length
					&& z < lotArray[NewestOrders[tmpIndex].getLotNo() - 1]
							.getZ(); z++) {
				for (int x = 0; tmpIndex < NewestOrders.length
						&& x < lotArray[NewestOrders[tmpIndex].getLotNo() - 1]
								.getX(); x++) {
					if (lotArray[NewestOrders[tmpIndex].getLotNo() - 1]
							.getLocation(x, y, z) == 0
							|| lotArray[NewestOrders[tmpIndex].getLotNo() - 1]
									.getLocation(x, y, z) == 1) {
						lotArray[NewestOrders[tmpIndex].getLotNo() - 1]
								.setLocation(x, y, z, 1);
						// build a new updated bean and update it in database
						tmpParking.setLotNo(NewestOrders[tmpIndex].getLotNo());
						tmpParking.setCarNo(NewestOrders[tmpIndex].getCarNo());
						tmpParking.setFloorNo(z);
						tmpParking.setPositionX(x);
						tmpParking.setPositionY(y);
						tmpParking.setStatus(1);
						AdminParking.insert(tmpParking);
						tmpIndex++;
					}

				}
			}
		}
	}

	/****
	 * AddTemporaryOrder**
	 * 
	 * Check user validity against DB and insert a temporary user
	 * 
	 * @param msg
	 * @return void 
	 */
	public void AddTemporaryOrder(Object msg) {
		Message tempMsg = (Message) msg;
		double amountToPay = 0;
		try {
			Orders o = (Orders) tempMsg.getObj();

			// check if an Occasional customer with this ID exists
			Customer bean = AdminCustomer.getRow(o.getUid());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such User Does Not Exist");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);
			// check that entered times are after current time
			if (currTimestamp.getTime() > o.getLeaveTime().getTime()
					&& currTimestamp.getTime() > o.getStartTime().getTime()
					&& o.getLeaveTime().getTime() > o.getStartTime().getTime()) {
				liste.add("ERROR:Temporary User Has Entered Invalid Leave Time");
				tempMsg.setStatusMsg("Times must be aftr current time");
				return;
			}
			if (AdminOrders.getLotStatus(o) == lotArray[o.getLotNo() - 1]
					.getCapacity()) {
				liste.add("ERROR:Temporary User Tried To Order While Lot Is Full");
				tempMsg.setStatusMsg("Sorry,But Lot Is Full At That Time");
				return;
			}
			if (AdminOrders.insert(o)) {
				System.out.println("start"+o.getStartTime()+",leaveTime:"+o.getLeaveTime());

				// make payment for parking
				amountToPay = calculatePayment(o);
				AdminCustomer
						.update(o.getUid(),
								AdminCustomer.getOccasionalRow(o.getUid())
										.getAmount() - amountToPay);
				tempMsg.setStatus(true);
				liste.add("Temorary Client Has Added Order No."
						+ ((Orders) tempMsg.getObj()).getOid());
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * AddFullSubscriber**
	 * Add new Full subscription to DB
	 * 
	 * @param msg
	 * @return void
	 */
	private void AddFullSubscriber(Object msg) {
		Message tempMsg = (Message) msg;
		double amountToPay = 0;
		try {
			Subscriber s = (Subscriber) tempMsg.getObj();

			Customer bean = AdminCustomer.getRow(s.getCusID());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such User Does Not Exist");
				return;
			}
			Subscriber s2 = AdminSubscriber.getRow(s.getCusID(), s.getCarNo());
			if (s2 != null) {
				liste.add("ERROR:Such Subscriber Already Exists");
				tempMsg.setStatusMsg("Such Subscriber Already Exists");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);

			// check that entered times are after current time
			if (currTimestamp.getTime() - 86400000 > s.getSubStart().getTime()) {
				liste.add("ERROR:Invalid Date Input was entered by subscriber");
				tempMsg.setStatusMsg("Times must be after current time");
				return;
			}
			Random rand = new Random();
			int randLot = rand.nextInt(6) + 1;
			s.setLotNo(randLot);
			if (AdminSubscriber.insertFull(s)) {
				// make payment for subscription
				amountToPay = calculateSubscriberPayment(s);
				AdminCustomer.update(s.getCusID(), AdminCustomer
						.getOccasionalRow(s.getCusID()).getAmount()
						- amountToPay);
				tempMsg.setStatus(true);
				s.setStatus(0);
				liste.add("New Full Subscriber Has Been Added To The System.");
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * AddRegularSubscriber**
	 * 
	 * Add new Regular subscription to DB
	 * 
	 * @param msg
	 * @return void 
	 */
	private void AddRegularSubscriber(Object msg) {
		Message tempMsg = (Message) msg;
		float amountToPay;
		try {
			Subscriber s = (Subscriber) tempMsg.getObj();
			Customer bean = AdminCustomer.getRow(s.getCusID());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid ID");
				tempMsg.setStatusMsg("Such Customer Does Not Exist");
				return;
			}
			Subscriber s2 = AdminSubscriber.getRow(s.getCusID(), s.getCarNo());
			if (s2 != null) {
				liste.add("ERROR:Such Subscriber Already Exists");
				tempMsg.setStatusMsg("Such Subscriber Already Exists");
				return;
			}
			long time = System.currentTimeMillis();// Set current time at this
													// second to StartTime
			Timestamp currTimestamp = new Timestamp(time);

			// check that entered times are after current time
			if (currTimestamp.getTime() > s.getSubStart().getTime()) {
				liste.add("ERROR:Invalid Date Input was entered by subscriber");
				tempMsg.setStatusMsg("Times must be after current time");
				return;
			}
			// Generate today's date to build Timestamp for today's leave time
			Calendar calendar = Calendar.getInstance();
			int day = calendar.get(Calendar.DAY_OF_MONTH);
			int year = calendar.get(Calendar.YEAR);
			int month = calendar.get(Calendar.MONTH) + 1;

			@SuppressWarnings("deprecation")
			Timestamp temp = customTimestamp.makeTimestamp(year, month, day, s
					.getTmp().getHours(), s.getTmp().getMinutes(), 00, 00);
			s.setLeaveTime(temp);

			if (AdminSubscriber.insertRegular(s)) {
				// make payment for subscritpion
				amountToPay = calculateSubscriberPayment(s);
				AdminCustomer.update(s.getCusID(), AdminCustomer
						.getOccasionalRow(s.getCusID()).getAmount()
						- amountToPay);
				tempMsg.setStatus(true);
				s.setStatus(0);
				liste.add("New Regular Subscriber Has Been Added To The System.");
			} else {
				tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * CancelOrder**
	 * 
	 * User can cancel his order through here
	 * 
	 * @param msg
	 * @return void 
	 */
	public void CancelOrder(Object msg) {
		// get current Timestamp of server
		long time = System.currentTimeMillis();
		Timestamp currTimestamp = new Timestamp(time);
		float amountToPay = 0;

		Message tempMsg = (Message) msg;
		Orders o = (Orders) tempMsg.getObj();// Get order object

		try {
			// find the customer order by id
			int id = o.getOid();

			// check if such order exists in DB and get it
			Orders tmpOrder = new Orders();
			tmpOrder = AdminOrders.getRow(id);
			if (tmpOrder == null) {
				liste.add("ERROR:User Has Entered An Invalid Order ID");
				tempMsg.setStatus(false);
				tempMsg.setStatusMsg("You Have Entered An Invalid Order ID");
				return;
			}
			if(tmpOrder.getStatus() == 3)
			{
				liste.add("ERROR:This Order Has Already Been Canceled - Aborting");
				tempMsg.setStatus(false);
				tempMsg.setStatusMsg("This Order Has Already Been Canceled - Aborting");
				return;	
			}
			// get current amount of customer account
			amountToPay = calculatePayment(tmpOrder);
			// save user scheduled parking Timestamp
			Timestamp tmpParking = tmpOrder.getStartTime();
			// check if parking is being cancelled 3 hours(108000000
			// milliseconds) before its beginning
			if (tmpParking.getTime() > currTimestamp.getTime() +10800000 ) {
				// give money back to user (compensate 100%)
				amountToPay = calculatePayment(tmpOrder);
				AdminCustomer.update(tmpOrder.getUid(),
						AdminCustomer.getRow(tmpOrder.getUid()).getAmount()
						+ (float) (amountToPay));
				System.out.println("case 1");

			} else if ((tmpOrder.getStartTime().getTime() - 3600000 > currTimestamp
					.getTime() && tmpOrder.getStartTime().getTime() - 10800000 < currTimestamp
					.getTime() ))
			// user has canceled Order between 1-3 hours before beginning - 50%
			// fine is given to user(1 hour = 3600000ms)
			{
				// give money back to user (compensate 100%)
				
				amountToPay = calculatePayment(tmpOrder);
				AdminCustomer.update(tmpOrder.getUid(),
						AdminCustomer.getRow(tmpOrder.getUid()).getAmount()
						+ (float) (amountToPay * 0.5));
				System.out.println("case 2");
				System.out.println(amountToPay);
			}

			// Set order status to canceled
			tmpOrder.setStatus(3);
			AdminOrders.update(tmpOrder);
			AdminCanceledOrders.insert(o);
			tempMsg.setStatus(true); // Order Cancellation was successful
			liste.add("User has cancelled order No." + o.getOid());

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * SubmitComplaint**
	 * 
	 * Check order validity against DB and insert a new complaint
	 * 
	 * @param msg
	 * @return void 
	 */
	private void SubmitComplaint(Object msg) {
		long time = System.currentTimeMillis();
		Timestamp currTimestamp = new Timestamp(time);
		Message tempMsg = (Message) msg;

		Complaints complaint = (Complaints) tempMsg.getObj();
		complaint.setTimestamp(currTimestamp);
		complaint.setStatus(0); // new complaint
		complaint.setAmount(0);

		int id = complaint.getOrderID();
		liste.add("insertComplait" + id);
		Orders order = new Orders();
		try {
			order = AdminOrders.getRow(id); // get the order detail from data
											// base
			if (order == null) {
				tempMsg.setStatusMsg("There Is no such id");
				liste.add("ERROR:User Has Entered An Invalid ID");
				return;
			}
			complaint.setCustomerID(order.getUid());
			AdminComplaints.insert(complaint);
			tempMsg.setStatusMsg("Your Complaint is Submitted, We Will Contact You Within 24 Hours");
			liste.add("User " + order.getUid() + " Has Submitted a Complaint");
			tempMsg.setStatus(true); // Complaint was successful
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.toString() + " SimpleServer->SubmitComplaint");
		}
	}

	/****
	 * TrackOrder**
	 * 
	 * Get Tracking Information of Order
	 * 
	 * 
	 * @param msg
	 * @return void 
	 */
	private void TrackOrder(Object msg) {
		Message tempMsg = (Message) msg;
		try {
			Orders o = (Orders) tempMsg.getObj();

			Orders bean = AdminOrders.getRow(o.getOid());
			if (bean == null) {
				liste.add("ERROR:User Has Entered An Invalid Order ID");
				tempMsg.setStatusMsg("Such Order Does Not Exist");
				return;
			}
			tempMsg.setStatus(true);
			liste.add("User Requested Order Tracking Of Order No." + o.getOid());
			o.setStatus(bean.getStatus());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * Login**
	 * 
	 * Authenticate Employee when Login into system occurs
	 * 
	 * @param msg
	 * @return void 
	 */
	private void Login(Object msg) {
		Message tempMsg = (Message) msg;
		Employee bean = null;
		try {
			Employee emp = new Employee();
			emp = (Employee) tempMsg.getObj();
			bean = AdminEmployee.getRow(emp.getUsername(), emp.getPassword());
			if (bean == null) {
				liste.add("ERROR:User Has Tried To Login To System With Invalid Details");
				tempMsg.setStatusMsg("User And Password Are Wrong,Please Try Again");
				tempMsg.setStatus(false);
				tempMsg.setMsg("Login");
			} else {
				// tempMsg.setStatus(true);
				// e.setType(bean.getType());
				// e.setEmpName(bean.getEmpName());
				liste.add("User " + bean.getEmpID() + " logs in.");
				tempMsg.setStatus(true);
				// tempMsg.setStatusMsg("OK");
				tempMsg.setMsg("Login");
				tempMsg.setObj(bean);
			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * Check In Regular**
	 * 
	 * Check In Regular Client Into System In this case only a user
	 *         with a temporary order may enter. this user has already paid for
	 *         parking.
	 *         
	 * @param msg
	 * @return void 
	 */
	public void CheckInRegular(Object msg) {
		Message tempMsg = (Message) msg;
		float amountToPay = 0;
		try {
			Orders o = (Orders) tempMsg.getObj();

			long time = System.currentTimeMillis();
			Timestamp currTimestamp = new Timestamp(time);

			Orders bean = AdminOrders.getRow(o.getOid());
			if (bean == null) {
				liste.add("ERROR:This User ID Did Not Make Any Orders");
				tempMsg.setStatusMsg("Such Order Does Not Exist - CheckIn Aborted");
				return;
			}
			// Occasional user which is already parking
			if (bean.getStatus() == 1) {
				liste.add("ERROR:User " + bean.getUid()
						+ " Tried To Login Twice");
				tempMsg.setStatusMsg("You Can't CheckIn Twice,Sorry.");
				return;
			}
			if (bean.getStatus() == 3) {
				liste.add("ERROR:User " + bean.getUid()
						+ " Tried To Use Canceled Order");
				tempMsg.setStatusMsg("This Order Has Been Cancled - Login Aborted.");
				return;
			}
			if (bean.getType().equals("Occasional")) {
				liste.add("ERROR:Occasional User Tried To Check In");
				tempMsg.setStatusMsg("Occasionals Users Can't Check In");
				return;
			}
			// if subscriber came before his start time
			if ((currTimestamp.getTime() < bean.getStartTime().getTime())) {
				liste.add("ERROR:Customer " + bean.getUid()
						+ " Came Before His Parking Hours");
				tempMsg.setStatusMsg("Sorry, But You Can't Park Before The Ordered Time");
				return;
			}
			// if regular subcriber came after his leave time
			if ((currTimestamp.getTime() > bean.getLeaveTime().getTime())) {
				liste.add("ERROR:Customer " + bean.getUid()
						+ " Came After His Parking Hours");
				tempMsg.setStatusMsg("Sorry, But You Can't Park After Your Regular Park Time");
				return;
			}
			// Check if lot if full
			if (lotArray[bean.getLotNo() - 1].getTotalCars() == lotArray[bean
					.getLotNo() - 1].getCapacity()) {
				// direct client to alternative lot
				int redirctionLot = 0;
				for (int i = 1; i <= ParkingLotNum; i++) {
					if (lotArray[i - 1].getTotalCars() < lotArray[i - 1]
							.getCapacity()) {
						redirctionLot = i;

					}

				}
				if (redirctionLot == 0)
					tempMsg.setStatusMsg("No Free Lots At The Moment");
				else {

					liste.add("ERROR:Parking Lot Is Full,Sending User To Lot No"
							+ redirctionLot);
					tempMsg.setStatusMsg("Sorry,But This Parking Lot Is Full,Please Go To Lot "
							+ redirctionLot);
				}
				return;
			} else {
				// add user to lot
				lotArray[bean.getLotNo() - 1].printLocastions();
				lotArray[bean.getLotNo() - 1].setTotalCars(lotArray[bean
						.getLotNo() - 1].getTotalCars() + 1);
				ParkingLotAdmin.update(bean.getLotNo(),
						lotArray[bean.getLotNo() - 1].getTotalCars());

			}

			if (currTimestamp.getTime() > bean.getStartTime().getTime() + 1800000000
					&& bean.getType().equals("Temporary")) {
				// user is late for parking and receives a fine - supposed to be
				// in SMS.
				amountToPay = calculatePayment(bean);
				float fine = (float) (amountToPay * 0.2);
				AdminCustomer.update(o.getUid(), AdminCustomer
						.getOccasionalRow(o.getUid()).getAmount()
						- amountToPay
						- fine);
			}
			bean.setStatus(1);
			if(AdminOrders.update(bean)){
			AdminCheckInOut.insertCheckIn(bean.getOid(), currTimestamp);
			Orders[] NewestOrders = AdminOrders.getRow(currTimestamp,
					bean.getLotNo());
			int orderIndex = 0;
			locateParking(NewestOrders, orderIndex, bean.getLotNo());
				tempMsg.setStatus(true);
				liste.add("User " + o.getUid() + " Has Entered Lot No."
						+ bean.getLotNo());
				tempMsg.setStatusMsg("Welcome To Lot No." + bean.getLotNo());
			} else {
				tempMsg.setStatus(false);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * Check In Subscriber**
	 * 
	 * Check In Subscriber Into System
	 * 
	 * @param msg
	 * @return void 
	 */
	@SuppressWarnings("deprecation")
	private void CheckInSubscriber(Object msg) {
		Message tempMsg = (Message) msg;
		try {
			Subscriber s = (Subscriber) tempMsg.getObj();
			Orders newOrder = new Orders();

			long time = System.currentTimeMillis();
			Timestamp currTimestamp = new Timestamp(time);
			Timestamp endDay = new Timestamp(time);
			Timestamp newTime = new Timestamp(time);

			Subscriber bean = AdminSubscriber
					.getRow(s.getSubID(), s.getCarNo());
			if (bean == null) {
				liste.add("ERROR:Subscriber Does Not Exists");
				tempMsg.setStatusMsg("Such Subscription Does Not Exist- CheckIn Aborted");
				return;
			}
			// Occasional user which is already parking
			if (bean.getStatus() == 1) {
				liste.add("ERROR:Subscriber " + s.getSubID()
						+ " Tried To Login Twice");
				tempMsg.setStatusMsg("You Can't CheckIn Twice,Sorry.");
				return;
			}
			if (bean.getStatus() == 3) {
				liste.add("ERROR:Subscriber " + s.getSubID()
						+ " Tried To Use Canceled Order");
				tempMsg.setStatusMsg("This Order Has Been Cancled - Login Aborted.");
				return;
			}
			// if Regular Customer came on weekend.
			
			  if( (bean.getType().equals("Regular") && (currTimestamp.getDay()== 6 || currTimestamp.getDay() ==7 ) ) ) {
			  liste.add("ERROR:Subscriber " + s.getSubID() +
			  " Tried To Enter Lot On Weekend - Aborted");
			  tempMsg.setStatusMsg("Sorry, But You Can't Enter A Lot On Weekends"); 
			  return;
			  }
			 
			// if regular subcriber came after his leave time
			if ((bean.getType().equals("Regular")
					&& (currTimestamp.getDate() == bean.getLeaveTime()
							.getDate()) && (currTimestamp.getTime() > bean
					.getLeaveTime().getTime()))) {
				liste.add("ERROR:Subscriber " + s.getSubID()
						+ " Came After His Parking Hours");
				tempMsg.setStatusMsg("Sorry, But You Can't Park After Your Regular Park Time");
				return;
			}
			// check that regular subscriber has parked in lot only one time
			// this week
			if ((bean.getType().equals("Regular")
					&& (bean.getLastLogin() != null) && (bean.getLastLogin()
					.getTime() + 604800000 > currTimestamp.getTime()))) {
				liste.add("ERROR:Subscriber " + s.getSubID()
						+ " Tried To Park Twice A Week");
				tempMsg.setStatusMsg("Sorry, But You Can't Park Twice A Week In This Lot");
				return;
			}
			// check that subscription isn't over - 28 days
			Calendar cal = Calendar.getInstance();
			cal.setTime(bean.getSubStart());
			cal.add(Calendar.DAY_OF_MONTH, 28); // add day for the first week
			endDay.setTime(cal.getTime().getTime()); // add day for the first
														// week

			if (endDay.getTime() < currTimestamp.getTime()) {
				liste.add("ERROR:Subscriber " + s.getSubID()
						+ " Has Tried To Check In After Subscrption END");
				tempMsg.setStatusMsg("Sorry, But Your Subscripton is over");
				return;

			}
			// check that subscriber came after his subscriptin start time
			if (currTimestamp.getTime() >= bean.getSubStart().getTime()) {
				newOrder.setLeaveTime(bean.getLeaveTime());
			} else {
				liste.add("ERROR:Regular Subscriber Tried To Enter Lot Before Intended Leave Time");
				tempMsg.setStatusMsg("You can't enter lot at this time.");
				return;
			}

			// TODO: what happens to FULL subscriber -> lot is taken from object

			bean.setStatus(1); // change user status to active parking
			bean.setLastLogin(currTimestamp);
			if (AdminSubscriber.updateLastLogin(bean)) {
				newOrder.setUid(bean.getCusID());
				newOrder.setCarNo(bean.getCarNo());
				if (bean.getType().equals("Full")) {
					newOrder.setType("Full");
					Calendar cal2 = Calendar.getInstance();
					cal2.setTime(bean.getSubStart());
					cal2.add(Calendar.DAY_OF_MONTH, 14); // add day for the
															// first week
					newTime.setTime(cal.getTime().getTime()); // add day for the
																// first week
					newOrder.setLeaveTime(newTime);
					newOrder.setStartTime(currTimestamp);
					newOrder.setLotNo(1);
					newOrder.setEmail("subs@s.com");

				} else {
					newOrder.setType("Regular");
					newOrder.setCarNo(bean.getCarNo());
					newOrder.setStartTime(currTimestamp);
					newOrder.setLeaveTime(bean.getLeaveTime());
					newOrder.setLotNo(bean.getLotNo());
					newOrder.setEmail("subs@s.com");
				}
				newOrder.setStatus(1);
				AdminOrders.insert(newOrder);
				AdminCheckInOut.insertCheckIn(newOrder.getOid(), currTimestamp);
				Orders[] NewestOrders = AdminOrders.getRow(currTimestamp,
						newOrder.getLotNo());
				int orderIndex = 0;
				locateParking(NewestOrders, orderIndex, newOrder.getLotNo());
				tempMsg.setStatus(true);
				liste.add("Subscriber " + s.getSubID() + " Has Entered Lot No."
						+ newOrder.getLotNo());
				tempMsg.setStatusMsg("Welcome To Lot No." + newOrder.getLotNo());

			} else {
				tempMsg.setStatus(false);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/****
	 * Check Out**
	 * 
	 * Check out user from system
	 * 
	 * @param msg
	 * @return void 
	 */
	public void CheckOut(Object msg) {
		Message tempMsg = (Message) msg;
		float amountToPay = 0;
		try {
			Orders o = (Orders) tempMsg.getObj();

			long time = System.currentTimeMillis();
			Timestamp currTimestamp = new Timestamp(time);

			Orders bean = AdminOrders.getRow(o.getUid(), o.getCarNo());
			if (bean == null) {
				liste.add("ERROR:Invalid User- - CheckOut Aborted");
				tempMsg.setStatusMsg("Such User Does Not Exist - CheckIn Aborted");
				return;
			}
			if (bean.getStatus() == 0 || bean.getStatus() == 3) {
				liste.add("ERROR:User Tried To CheckOut Before Checking In");
				tempMsg.setStatusMsg("Can't Check Out Before Checking In - CheckIn Aborted");
				return;
			}
			

			// get LotNumber and Decrement User From Lot
			lotArray[bean.getLotNo() - 1]
					.setTotalCars(lotArray[bean.getLotNo() - 1].getTotalCars() - 1);
			ParkingLotAdmin.update(bean.getLotNo(),
					lotArray[bean.getLotNo() - 1].getTotalCars());

			// If user that pre-ordered is exiting after leaveTime - Gets a fine
			// of paying 1.5 of order price
			if (bean.getType().equals("Temporary")
					&& currTimestamp.getTime() > bean.getLeaveTime().getTime()) {
				amountToPay = calculatePayment(bean);
				// make adjustments to previous payment made on the internet
				float adjust = (float) (amountToPay * 1.5);
				AdminCustomer.update(bean.getUid(), AdminCustomer
						.getOccasionalRow(bean.getUid()).getAmount()
						+ amountToPay - adjust);
				
				System.out.println("inside");

			}

			// If user that pre-ordered is exiting after leaveTime - Gets a fine
			// of paying 1.5 of order price
			if (bean.getType().equals("Temporary")
					&& AdminSMS.smsFine(bean.getOid())) {

				amountToPay = calculatePayment(bean);

				// give 20% fine of the total amount for being late to the
				// ordered parking
				float fine = (float) (amountToPay * 0.2);
				System.out.println(fine);
				AdminCustomer.update(bean.getUid(), AdminCustomer
						.getOccasionalRow(bean.getUid()).getAmount() - fine);

			}

			if (bean.getType().equals("Occasional")) {
				amountToPay = calculatePayment(bean);
				// make adjustments to previous payment made on the internet
				AdminCustomer.update(bean.getUid(), AdminCustomer
						.getOccasionalRow(bean.getUid()).getAmount()
						- amountToPay);
			}
			if (bean.getType().equals("Regular")) {
				Subscriber s = AdminSubscriber.getRow(bean.getUid(),
						bean.getCarNo());
				AdminSubscriber.updateLastLogin(s);

			}
			bean.setStatus(2); // change user status to finished parking
			if (AdminOrders.update(bean)) {
				Parking p = new Parking();
				p = AdminParking.getRow(bean.getCarNo());
				AdminParking.delete(p.getLotNo(), p.getPositionX(),
						p.getPositionY(), p.getFloorNo());
				lotArray[p.getLotNo() - 1].setLocation(p.getPositionX(),
						p.getPositionY(), p.getFloorNo(), 0);
				Orders[] NewestOrders = AdminOrders.getRow(currTimestamp,
						bean.getLotNo());
				int orderIndex = 0;
				lotArray[bean.getLotNo() - 1].printLocastions();
				locateParking(NewestOrders, orderIndex, bean.getLotNo());
				tempMsg.setStatus(true);
				lotArray[bean.getLotNo() - 1].printLocastions();
				AdminCheckInOut.insertCheckOut(bean.getOid(), currTimestamp);
				liste.add("User " + bean.getUid() + " Has Left Lot No."
						+ bean.getLotNo());
				tempMsg.setStatusMsg("Thank You For Using The Services Of Lot No."
						+ bean.getLotNo());

			} else {
				tempMsg.setStatus(false);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/****
	 * Create Report**
	 * 
	 * insert new report
	 * 
	 * @param msg
	 * @return void 
	 */
	private void CreateQuarterReport(Object msg) {
		Message tempMsg = (Message) msg;
		QuarterReports report =  (QuarterReports) tempMsg.getObj();
		try {
			if(AdminReports.insertQuarterReports(report)){
				liste.add("CreateQuarterReport::OK");
				tempMsg.setMsg("CreateQuarterReport");
				tempMsg.setStatus(true);
			}else{
				 liste.add("CreateQuarterReport::ERROR");
				 tempMsg.setStatusMsg("CreateQuarterReport::ERROR");
				 tempMsg.setMsg("CreateQuarterReport");
				 tempMsg.setStatus(false);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	
	/**
	 * Get Quarterly report from system
	 * @param msg
	 */
	private void GetQuarterReport(Object msg) {
		Message tempMsg = (Message) msg;
		QuarterReports report = (QuarterReports) tempMsg.getObj();
		Timestamp startTime = null;
		Timestamp leaveTime = null;
		
		Calendar cal = GregorianCalendar.getInstance();
		Calendar cal2 = GregorianCalendar.getInstance();
		cal.set(Calendar.YEAR, report.getYear());
		cal2.set(Calendar.YEAR, report.getYear());		
		
		
		if (report.getQuarter()==1 ) { // first quarter
			startTime= Timestamp.valueOf(report.getYear()+"-01-01 00:00:00.0");		//set start of first quarter 
			leaveTime= Timestamp.valueOf(report.getYear()+"-04-01 00:00:00.0");		//set end of first quarter
		}
		
		else if (report.getQuarter()==2 ) { // second quarter
			startTime= Timestamp.valueOf(report.getYear()+"-04-01 00:00:00.0"); 	//set start of second quarter
			leaveTime= Timestamp.valueOf(report.getYear()+"-07-01 00:00:00.0");		//set end of second quarter
		} else if (report.getQuarter() == 3) { // third quarter
			startTime= Timestamp.valueOf(report.getYear()+"-07-01 00:00:00.0"); 	//set start of third quarter
			leaveTime= Timestamp.valueOf(report.getYear()+"-10-01 00:00:00.0");		//set end of third quarter
			
		} else if (report.getQuarter() == 4) { // forth quarter
			int newYear =report.getYear()+1;
			startTime= Timestamp.valueOf(report.getYear()+"-10-01 00:00:00.0"); 	//set start of forth quarter
			leaveTime= Timestamp.valueOf(newYear+"-01-01 00:00:00.0");				//set end of third quarter(new year)
		}
		
		Orders[] retOrders = null;
		Complaints[] complaints=null;
		try {
			switch (report.getReportName()) {
			case "Orders":
				retOrders= AdminOrders.getOrdersDuringTimeBylotNo(startTime,leaveTime,report.getLotNo());
				if(retOrders!=null){
					liste.add("GetQuarterReport::OK");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setObj(retOrders);
					tempMsg.setStatus(true);
				}else{
					liste.add("GetQuarterReport::ERROR");
					tempMsg.setStatusMsg("GetQuarterReport::ERROR");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setStatus(false);
				}
				break;

			case "Complaints":
				complaints=  AdminComplaints.getComplaintDuringTimeBylotNo(startTime,leaveTime,report.getLotNo());
				if(complaints!=null){
					liste.add("GetQuarterReport::OK");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setObj(complaints);
					tempMsg.setStatus(true);
				}else{
					liste.add("GetQuarterReport::ERROR");
					tempMsg.setStatusMsg("GetQuarterReport::ERROR");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setStatus(false);
				}
				break;

			case "Disabled parking":
				SaveDisableParking []savdisable= AdminSaveDisableParking.getAllReport(startTime, leaveTime,report.getLotNo());
				if(savdisable!=null){
					liste.add("GetQuarterReport::OK");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setObj(savdisable);
					tempMsg.setStatus(true);
				}else{
					liste.add("GetQuarterReport::ERROR");
					tempMsg.setStatusMsg("GetQuarterReport::ERROR");
					tempMsg.setMsg("GetQuarterReport");
					tempMsg.setStatus(false);
				}
				break;

			default:
				break;
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	
	

	// help functions
	/**
	 * Functions Calculates payment that should be done by Occasional Or Temporary user
	 * which is calculcated based on parking times.
	 * 
	 * @param tmpOrder-order which we calculate the amount to pay for.
	 * @return
	 * @throws Exception
	 */
	public float calculatePayment(Orders tmpOrder) throws Exception {
		float amountToPay = 0;
		int rateType;
		int minutes = 0;
		// find the pricing of the current lot
		if(tmpOrder == null)
		{
			throw new InvalidException("Object is Null");			
		}
		int[] lotPriceArray = lotArray[tmpOrder.getLotNo() - 1].getPrices();

		if(tmpOrder.getStartTime().getTime() > tmpOrder.getLeaveTime().getTime())
		{
			throw new InvalidException("Start Time Can't Be After Leave Time");
			
		}
		rateType = rateByType(tmpOrder.getType());
		if (rateType == 0 || rateType == 1) {
			// calculate hourly rate
			minutes = (int) TimeUnit.MILLISECONDS.toMinutes(tmpOrder
					.getLeaveTime().getTime()
					- tmpOrder.getStartTime().getTime());
			amountToPay = (float) Math.floor((float) lotPriceArray[rateType]
					* ((float) minutes / 60));
		}
		else
			throw new InvalidException("Unknown Customer Type");

		return amountToPay;
	}

	/**
	 * Functions which calculates the amount that should be paid by Subscribed users.
	 * 
	 * @param s - Subscriber object for which we want to calculate the amount for.
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("deprecation")
	public float calculateSubscriberPayment(Subscriber s) throws Exception {
		float amountToPay = 0;
		int rateType;
		
		long time = System.currentTimeMillis();// Set current time at this second to StartTime
		Timestamp currTimestamp = new Timestamp(time);

		// find the pricing of the current lot
		if(s == null)
		{
			throw new InvalidException("Object is Null");			
		}
		if(s.getSubStart().getTime() < currTimestamp.getTime())
		{
			throw new InvalidException("Error:Subscription hasn't started yet");			
		}
		if(s.getSubStart().getMonth() + 1 < currTimestamp.getMonth() && s.getSubStart().getTime() < currTimestamp.getTime() )
		{
			throw new InvalidException("Error:Please Renew Your Subscription");			
		}
		
		int[] lotPriceArray = lotArray[s.getLotNo() - 1].getPrices();

		rateType = rateByType(s.getType());
		// if regular subscriber check how many cars he has in lot
		if (rateType == 2) {
			// get customer object to get num of cars
			Customer c = AdminCustomer.getRow(s.getCusID());

			if (c.getNumOfCars() < 2) {
				amountToPay = lotPriceArray[rateType];
			} else if (c.getNumOfCars() >= 2) {
				amountToPay = (float) ((lotPriceArray[rateType] * c
						.getNumOfCars()) * 0.9);
			}
			// Calculate estimated parking time

		}

		else if (rateType == 4)
			amountToPay = 72 * lotPriceArray[1];
		else
			throw new InvalidException("Unknown Customer Type");
		

		return amountToPay;
	}

	/**
	 * Functions receives a user type and return its Enumeration.
	 * 
	 * @param type - user type
	 * @return
	 */
	private int rateByType(String type) {

		switch (type) {
		case "Occasional":
			return 0;
		case "Temporary":
			return 1;
		case "Regular":
			return 2;
		case "Full":
			return 4;
		default:
		}
		return -1;
	}

	/**
	 * Functions which initializes the Lot object which leaves throghout all the time the 
	 * server is alive.we use this object to return and control data faster.
	 * 
	 * 
	 * @throws SQLException
	 */
	private void InitParkingLot() throws SQLException {
		lotArray = new ParkingLot[ParkingLotNum];
		rates rateDB[] = AdminRates.getRows();
		Parking parkDB[] = AdminParking.getRows();

		for (int i = 0; i < ParkingLotNum; i++) // get lots deatails eithout
												// locations
		{
			ParkingLot dbLot = ParkingLotAdmin.getRow(i + 1);
			lotArray[i] = new ParkingLot(dbLot);
		}

		for (int j = 0; j < 30; j++) {
			// MAX DO NOT ASK US!
			lotArray[rateDB[j].getLotNo() - 1].setPrices(rateDB[j].getAmount(),
					rateDB[j].getRateType() - 1);
		}

		for (int i = 0; i < parkDB.length; i++) {
			// MAX NOW REALLY DON'T ASK US!
			lotArray[(parkDB[i].getLotNo()) - 1].setLocation(
					parkDB[i].getPositionX(), parkDB[i].getPositionY(),
					parkDB[i].getFloorNo(), parkDB[i].getStatus());

		}
		// lotArray = Lot;
		liste.add("Parking lot initialized...");
	}
	
	/**
	 * Exception class to return customer exception messages.
	 *
	 */
	@SuppressWarnings("serial")
	public class InvalidException extends Exception {
		  public InvalidException(String message){
		     super(message);
		  }

		}

}
